import ProgramMenu, { type ProgramMenuProps } from "./ProgramMenu";
import ProgramDetail from "./ProgramDetail";
import { useState } from "react";
import useFetch from "@/lib/hooks/useFetch";
import {
  getProgramList,
  getProgramStatus,
  updateProgramStatus,
} from "@/lib/api/program";
import { useAtomValue } from "jotai";
import { tokenAtom } from "@/store/user";
import type { IProgram, IProgramStatus } from "@/lib/types";
import useOnUpdated from "@/lib/hooks/useOnUpdated";
import EditProgramStatusModal, {
  type EditType,
} from "./EditProgramStatusModal";
import { useMessage } from "@/providers/AntdMessageProvider";
import getKey from "./getKey";
import EditProgramCycleModal from "./EditProgramCycleModal";
import NavigatePrompt from "../NaviatePrompt";
import { useModal } from "@/providers/AntdModalProvider";
import getRequestErrorMessage from "@/lib/utils/getRequestErrorMessage";

type ProgramListProps = {
  editable?: boolean;
  onSelectProgram?: ProgramMenuProps["onSelectProgram"];
  onSelectedProgramStatusChange?: (
    program: IProgram,
    status?: IProgramStatus[],
  ) => void;
};

export default function ProgramList(props: ProgramListProps) {
  const { editable, onSelectProgram, onSelectedProgramStatusChange } = props;
  const [selected, setSelected] = useState<{
    program?: IProgram;
    status?: IProgramStatus[];
  }>({
    program: undefined,
    status: undefined,
  });
  const [editModal, setEditModal] = useState<{
    visible: boolean;
    type?: EditType;
    records?: IProgramStatus[];
    program?: IProgram;
  }>({
    visible: false,
    type: undefined,
    records: undefined,
    program: undefined,
  });
  const [editProgramCycleModalVisible, setEditProgramCycleModalVisible] =
    useState(false);

  const [edited, setEdited] = useState(false); // 是否编辑了某些字段但还未保存
  const [programStatus, setProgramStatus] = useState<IProgramStatus[]>([]);

  const token = useAtomValue(tokenAtom);
  const message = useMessage();
  const modal = useModal();

  async function handleSelectProgram(program: IProgram) {
    let canSelect = true;
    if (edited) {
      canSelect = await new Promise((resolve) => {
        modal.confirm({
          content: "当前更改尚未保存，确定离开吗？",
          okText: "确定",
          cancelText: "取消",
          closable: true,
          onOk() {
            resolve(true);
          },
          onCancel() {
            resolve(false);
          },
        });
      });
    }
    if (canSelect) {
      setEdited(false);
      setSelected({ program, status: undefined });
      onSelectProgram?.(program);
      onSelectedProgramStatusChange?.(program, undefined);
    }
    return canSelect;
  }

  function handleEditRecords(
    records: IProgramStatus[],
    column: "循环" | "时间" | "温度" | "湿度" | "压力" | "TS",
  ) {
    const data: typeof editModal = { visible: true, records };
    if (column === "循环") {
      data.type = "cycle";
    } else if (column === "时间") {
      data.type = "time";
    } else if (column === "温度") {
      data.type = "temperature";
    } else if (column === "湿度") {
      data.type = "humidity";
    } else if (column === "压力") {
      data.type = "pressure";
    } else {
      data.type = "ts";
    }
    setEditModal(data);
  }

  function handleEditRecordsFinish(records: IProgramStatus[]) {
    setEdited(true);
    setProgramStatus((p) =>
      p.map(
        (status) =>
          records.find((item) => getKey(item) === getKey(status)) || status,
      ),
    );
  }

  function handleEditProgram() {
    setEditProgramCycleModalVisible(true);
  }

  const {
    data: programs,
    isLoading: isLoadingPrograms,
    refetch: loadProgramList,
  } = useFetch({
    async fetchFn() {
      const search = new URLSearchParams(location.search);
      const programModelNo = search.get("pmn") || undefined;
      console.log({ programModelNo });
      return getProgramList({ modelNo: programModelNo }, token).then((res) => {
        if (res.code !== 200) {
          throw res;
        }
        return res.rows;
      });
    },
    onError(error) {
      message.error(getRequestErrorMessage(error));
    },
    immediate: true,
  });

  const {
    isPending: isPendingStatus,
    isLoading: isLoadingStatus,
    refetch: loadProgramStatus,
  } = useFetch({
    fetchFn: (id: number) =>
      getProgramStatus(id, token).then((res) => {
        if (res.code !== 200) {
          throw res;
        }
        return res.data;
      }),
    onSuccess(data) {
      setProgramStatus(data);
      setSelected((p) => ({ ...p, status: data }));
      onSelectedProgramStatusChange?.(selected.program!, data);
    },
  });

  const { isLoading: isSaving, refetch: handleSave } = useFetch({
    fetchFn: ({ id, data }) =>
      updateProgramStatus(id, data, token).then((res) => {
        if (res.code !== 200) {
          throw res;
        }
      }),
    initialPayload: { id: 0, data: [] as IProgramStatus[] },
    onSuccess() {
      message.success("保存成功");
      setEdited(false);
    },
    onError(error) {
      let _message = "保存失败！";
      if ("msg" in error) {
        _message = error.msg;
      } else if ("message" in error) {
        _message = error.message;
      }
      message.error(_message);
    },
  });

  function handleUpdateProgramStatus(
    update: (data: IProgramStatus[]) => IProgramStatus[],
  ) {
    setProgramStatus(update);
  }

  useOnUpdated(() => {
    selected.program && loadProgramStatus(selected.program.programId);
  }, [selected.program]);

  return (
    <>
      <NavigatePrompt shouldBlock={edited}>
        <p>当前更改尚未保存，确定离开吗？</p>
      </NavigatePrompt>
      <div className="flex h-full">
        <ProgramMenu
          editable={editable}
          loading={isLoadingPrograms}
          programs={programs || []}
          onSelectProgram={handleSelectProgram}
          reloadProgramList={loadProgramList}
        />
        <ProgramDetail
          editable={editable}
          loading={isPendingStatus || isLoadingStatus}
          program={selected.program}
          programStatus={programStatus}
          onEditRecords={handleEditRecords}
          onEditProgram={handleEditProgram}
          isSaving={isSaving}
          onSave={() =>
            selected.program &&
            handleSave({
              id: selected.program.programId,
              data: programStatus,
            })
          }
          onUpdateProgramStatus={handleUpdateProgramStatus}
        />
      </div>
      <EditProgramStatusModal
        visible={editModal.visible}
        type={editModal.type}
        records={editModal.records}
        onClose={() =>
          setEditModal({
            visible: false,
            type: undefined,
            records: undefined,
            program: undefined,
          })
        }
        onEditRecordsFinish={handleEditRecordsFinish}
      />
      <EditProgramCycleModal
        program={selected.program}
        visible={editProgramCycleModalVisible}
        onClose={() => setEditProgramCycleModalVisible(false)}
        onSuccess={(program) => setSelected((p) => ({ ...p, program }))}
      />
    </>
  );
}
